home *** CD-ROM | disk | FTP | other *** search
- Subject: v08i074: Shrink VeryLong+File.names to shorter names
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: simon2 <simon2@its63b.ed.ac.uk>
- Mod.sources: Volume 8, Issue 74
- Archive-name: shrink_names
-
- [ Blame me for the Makefile. --r$ ]
-
- Here is a very useful program for changing filenames from BSD filename
- form to a more portable form (14 char limit). It is reasonably
- intelligent as to what the structure of the original filename was, and
- tries quite hard to maintain this underlying structure by just
- shortening the subfields.
- Simon Brown
- Department of Computer Science, University of Edinburgh, Scotland.
- ...!{ihnp4,seismo,decvax}!mcvax!ukc!cstvax(!its63b?)!simon
-
- ------------------------- CUT HERE -------------------------------
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # shrink.1
- # shrink.c
- # Makefile
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'shrink.1'" '(2814 characters)'
- if test -f 'shrink.1'
- then
- echo shar: "will not over-write existing file 'shrink.1'"
- else
- cat << \SHAR_EOF > 'shrink.1'
- .TH SHRINK 1 "Edinburgh University" "December 1986"
- .SH NAME
- shrink \- generate short filenames from extended ones
- .SH SYNOPSIS
- .B shrink
- [ -vnSm ] [ -s\fIseparators\fR ] [ -\fIn\fR ] \fIfilename\fR ...
- .SH DESCRIPTION
- .I Shrink
- converts a filename to a shrunken form, suitable for transportation
- to another system with less generous filename length limits.
- It takes each
- .I filename
- given, and applies certain rules to shorten it, if necessary.
- In particular, it tries to leave suffixes unchanged, and,
- to a less extent, to keep the initial component as close to the
- original as possible. Of course, very long suffixes do have to be
- truncated.
- .PP
- The following options are recognized:
- .TP
- .B -v
- Verbose mode. Normally
- .I shrink
- does its work silently, but under the verbose option it chats about
- what decisions its making.
- .TP
- .B -n
- Normally the new filename is generated so as to not clash with an
- existing file, to prevent several long-named files folding into the
- same shortened form. This behaviour can be revoked by use of the
- .B -n
- option.
- .TP
- .B -s
- Normally the new filename is printed on the standard output.
- The
- .B -s
- option causes
- .I shrink
- to be silent.
- This is useful only in conjunction with the
- .B -m
- option.
- .TP
- .B -m
- This causes the files to be physically renamed;
- normally, just the ``suggested'' change is printed but nothing
- actually done.
- .TP
- .B "-s \fIseparators\fB"
- This can be used to change the set of
- .I separators
- that
- .I shrink
- recognizes.
- These are the characters that are used to delimit filename components.
- .I Shrink
- operates by shrinking characters out of each component
- (though it is loath to modify the first or last components unless
- it has no choice), while leaving the delimiters unchanged.
- However, if a filename contains a vast number of delimiter characters
- (such as
- .I this_file_contains_quite_a_lot_of_stuff_and_useful_stuff_at_that
- ), then some components (and their associated delimiters)
- will have to be deleted totally.
- The default delimiter set is
- .BR + ,
- .BR - ,
- .BR . ,
- .BR _ ,
- .BR ~
- and
- .BR , .
- .TP
- .B "-\fIn\fB"
- A numerical flag \fIn\fR may be given to specify a maximum length
- that the resultant filename is allowed to be.
- The default is 14 (which is the maximum file length under all unix
- systems without the Berkeley modified filesystem).
- .SH DIAGNOSTICS
- Under the
- .B -v
- option, lots of diagnostics can be produced.
- Those preceded by the word
- .B "``warning:''"
- can probably be ignored.
- .PP
- Under certain circumstances,
- .I shrink
- may refuse totally to deal with some filenames,
- though this is not very likely to occur unless a very small
- maximum length flag is specified.
- .SH BUGS
- If the file begins with a delimiter character,
- then
- .I shrink
- sometimes causes the shortened filename to be shorter than it
- need be.
- This is not too serious a bug.
- .SH AUTHOR
- Simon Brown.
- SHAR_EOF
- fi
- echo shar: "extracting 'shrink.c'" '(6420 characters)'
- if test -f 'shrink.c'
- then
- echo shar: "will not over-write existing file 'shrink.c'"
- else
- cat << \SHAR_EOF > 'shrink.c'
- /*
- * Rename a file so's it will be unique under systems without
- * extended filename size.
- * The new name is written on the stardard output.
- *
- * Example:
- * To copy lots of files from a 4.?BSD system to a
- * SystemV, SystemIII, 2.?BSD or V7 system, without
- * having to worry about overlapping filenames
- * (eg, so "what_a_long_filename.c" and "what_a_long_filename.h"
- * don't get squished), just do
- * for i in *
- * do
- * j=`shrink -m $i`
- * uucp $j othersys!/stuff/$j (or rcp, hhcp, ...)
- * done
- *
- * Bug: It gets overenthusiastic and deletes characters
- * unnecessarily if the filename begins with a "."
- *
- * Author:
- * Simon Brown
- * Department of Computer Science, University of Edinburgh.
- */
-
- #include <stdio.h>
-
- /*
- * maximum no. of "segments" allowed in a file
- */
- #define MAXSEGS 10
-
- /*
- * silly names for strchr/strrchr under non-usg unices
- */
- #ifndef sysV
- #define strchr index
- #define strrchr rindex
- #endif sysV
-
- char *getsegment();
- char *strchr(), *strrchr();
-
- struct segment {
- char seg_string[63];
- char seg_sep;
- } seg[MAXSEGS];
-
- char defaults[] = "._+-,@~=";
- char usagemsg[] = "Usage: %s [-<maxlength>] [-mnSv] [-s<separators>] filename ...\n";
-
- int max = 14; /* target length */
- int nocheck = 0; /* don't check for existance (-n flag) */
- int chatty = 0; /* talk a lot (-v flag) */
- int silent = 0; /* don't say anything (-s flag) */
- int move = 0; /* rename file (-m flag) */
- char *file, *prefix;
- int modified = 0;
- char realname[512];
- char *separators = defaults;
-
- main(argc,argv)
- char **argv;
- {
- register int i, j;
- int nsegs, suflen, remainder, delete;
- int total;
- int zap = 0;
- register char *op;
- char *progname = argv[0];
-
- if (argv[1] == (char *)0){
- fprintf(stderr, usagemsg, progname);
- exit(1);
- }
- while (*++argv) /* process command-line options... */
- if (**argv=='-')
- while (*++*argv)
- switch(**argv){
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8':
- case '9': /* change target length */
- max = atoi(*argv);
- if (max<=0){
- fprintf(stderr,"%s: illegal length %s\n", argv[0], argv[1]);
- exit(1);
- }
- while (*++*argv);
- --*argv;
- break;
- case 's': /* change separator definition */
- separators = ++*argv;
- while (*++*argv);
- --*argv;
- break;
- case 'n': /* don't create a uniquely named file */
- nocheck=1;
- break;
- case 'v': /* talk a lot */
- chatty=1;
- break;
- case 'm': /* move files */
- move=1;
- break;
- case'S': /* silent */
- silent=1;
- break;
- default:
- fprintf(stderr,usagemsg,progname);
- exit(1);
- }
- else break;
- while (*argv){
- strcpy(realname, *argv);
- if (prefix=strrchr(*argv,'/')){ /* dir/.../file */
- file=prefix+1;
- *prefix = '\0';
- prefix = *argv;
- } else file = *argv;
- argv++;
- op=file;
- modified=0;
- /* split into logical parts */
- for (i=0; i<MAXSEGS && (op=getsegment(op,i)); i++);
- if (i==MAXSEGS){
- fprintf(stderr,"%s: too many segments\n", file);
- continue;
- }
- nsegs = i-1;
- if ((nsegs*2) >= max){
- fprintf(stderr,"%s: too many segments\n", file);
- continue;
- }
- suflen = strlen(seg[nsegs].seg_string);
- if (suflen>max-nsegs-1){
- if (chatty)
- fprintf(stderr,"warning: %s: suffix truncated\n", file);
- suflen = max-(2*nsegs)-1;
- seg[nsegs].seg_string[suflen-1] = '\0';
- modified=1;
- } else if (suflen+nsegs > max-nsegs-1){
- zap = nsegs - (max-suflen)/2;
- if (chatty && zap)
- fprintf(stderr,"warning: %s: %d segments removed\n", file, zap);
- }
- if (nsegs>=1){ /* complicated filename */
- for (i=zap+1; i<=nsegs; i++)
- if (seg[i].seg_sep) suflen++;
- if (seg[0].seg_sep) suflen++;
- remainder = max - suflen;
- delete = remainder/nsegs;
- total = suflen;
- for (i=zap+1; i<nsegs; i++){
- if (strlen(seg[i].seg_string) > delete)
- modified=1;
- seg[i].seg_string[delete] = '\0';
- total += delete;
- }
- if (strlen(seg[0].seg_string) > max-total)
- modified=1;
- seg[0].seg_string[max-total] = '\0';
- }
- unique(zap,nsegs,modified);
- }
- }
-
- /*
- * get a segment from a filename.
- * returns pointer to remainder of filename, or 0 at end of filename
- */
- char *
- getsegment(cp,i)
- char *cp;
- {
- register char *xp = seg[i].seg_string;
- while (*cp && strchr(separators,*cp)==0)
- *xp++ = *cp++;
- *xp = '\0';
- seg[i].seg_sep = *cp;
- if (*cp) cp++;
- if (seg[i].seg_string[0] || seg[i].seg_sep) return(cp);
- else return((char *)0);
- }
-
-
- /*
- * print out the current filename in a unique form
- */
- unique(zap,n,mod)
- {
- register int i, j;
- int jmax[MAXSEGS];
- int xstart, xstop;
-
- if (ok(zap,zap||mod)) return;
- xstart = (n==0)? 0 : 1;
- xstop = (n==0)? 1 : n;
- more:
- if (xstop <= xstart){
- xstart=0;
- xstop = n+1;
- }
- for (i=xstart; i<xstop; i++)
- jmax[i] = strlen(seg[i].seg_string);
- for (j=0; j<5; j++){
- for (i=xstart; i<xstop; i++){
- if (j >= jmax[i]) continue;
- increment(seg[i].seg_string,j);
- if (ok(zap,1)) return;
- }
- }
- if (xstart>0 || xstop<n+1){ /* Desparation time: try _any_ segment! */
- xstop = -1;
- goto more;
- }
- fprintf(stderr,"Can't generate unique name for %s\n", file);
- }
-
- /*
- * modify a character in a string (stupid algorithm)
- */
- increment(str,ind)
- char *str;
- {
- char ch = str[ind];
-
- if (ch>='a' && ch<='z') ch += ('A'-'a');
- else if (ch>='A' && ch<='Z') ch += ('a'-'A');
- str[ind] = ch;
- }
-
-
- /*
- * see if a filename is reasonable, and if so print it out
- * and return 1.
- * otherwise return 0.
- */
- ok(zap,changed)
- {
- char buffer[512];
- register char *cp = buffer;
- register char *xp;
- register int i;
-
- if (prefix){
- for (xp=prefix; *xp; )
- *cp++ = *xp++;
- *cp++ = '/';
- }
- for (xp=seg[0].seg_string; *xp; ) /* copy initial segment */
- *cp++ = *xp++;
- if (seg[0].seg_sep){
- *cp++ = seg[0].seg_sep;
- for (i=zap+1; ; i++){ /* copy rest of segments */
- for (xp=seg[i].seg_string; *xp; )
- *cp++ = *xp++;
- if (seg[i].seg_sep) *cp++ = seg[i].seg_sep;
- else if (seg[i].seg_string[0] == '\0') break;
- }
- }
- *cp = '\0';
- if (changed && nocheck==0 && access(buffer,0)==0){
- if (chatty)
- fprintf(stderr,"warning: %s already exists - trying again\n",buffer);
- return(0);
- } else {
- if (silent==0) printf("%s\n", buffer);
- if (move && strcmp(realname,buffer)){
- if (link(realname,buffer)==-1 || unlink(realname)==-1)
- fprintf(stderr,"%s: link/unlink failure\n", realname);
- }
- return(1);
- }
- }
-
-
- SHAR_EOF
- fi
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- CFLAGS=-O
- shrink: shrink.c
- $(CC) $(CFLAGS) -o shrink shrink.c
- install: shrink
- @echo copy shrink.1 and shrink to appropriate directories
- SHAR_EOF
- fi
- exit 0
- # End of shell archive
- --
-